import { UnauthorizedException, Inject, Injectable } from "@nestjs/common";
import type { UserEntity } from "src/entity";
import { JwtSignOptions, JwtVerifyOptions, JwtService as SjwtService } from "@nestjs/jwt";
import { ConfigService } from "@nestjs/config";
import type { DownloadFileTokenInfo } from "src/file/service/file.service";
import { CACHE_MANAGER, Cache } from "@nestjs/cache-manager";
import { UserService } from "src/user/service/user.service";

@Injectable()
export class JwtService {
    private readonly fileJwtSignOptions: JwtSignOptions;

    constructor(
        @Inject(CACHE_MANAGER) private cacheManager: Cache,
        private readonly configService: ConfigService,
        private readonly userService: UserService,
        private readonly sJwtService: SjwtService,
    ) {
        this.fileJwtSignOptions = {
            secret: this.configService.get<string>("FILE_SECRET"),
            expiresIn: this.configService.get<number>("FILE_TOKEN_EXPIRED"),
        };
    }

    private verify<T extends object = any>(token: string, options?: JwtVerifyOptions): T {
        try {
            return this.sJwtService.verify<T>(token, options);
        } catch (error) {
            throw new UnauthorizedException(error.message || error);
        }
    }

    generateUserToken(user: UserEntity) {
        return this.sJwtService.signAsync({
            id: user.id,
            updateTime: user.updateTime,
        });
    }

    async verifyUserInfo(jwtInfo: JwtInfo) {
        const requsetUser = await this.userService.getRequestUser(jwtInfo.id);

        if (new Date(jwtInfo.updateTime).getTime() < new Date(requsetUser.updateTime).getTime()) {
            throw new UnauthorizedException("登录无效，请重新登录");
        }

        return requsetUser;
    }

    verifyUser(token: string) {
        return this.verifyUserInfo(this.verify<JwtInfo>(token));
    }

    generateFileToken(info: DownloadFileTokenInfo) {
        return this.sJwtService.signAsync(info, this.fileJwtSignOptions);
    }

    verifyFile(token: string) {
        return this.verify<DownloadFileTokenInfo>(token, this.fileJwtSignOptions);
    }
}
